Import rds-postgres-server and rds-postgres-db from nullplatform/services - #2
Merged
sebastiancorrea81 merged 37 commits intoJul 7, 2026
Merged
Conversation
Adds rds-postgres-db and rds-postgres-server service modules, each with deployment/permissions Terraform configs, entrypoints, workflow definitions (create/delete/link/unlink/update), scripts, and service specs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rm provider Replace hardcoded vpc_id in values.yaml with a runtime lookup from the nullplatform VPC provider. build_context now derives the account NRN from the service NRN, queries the provider that stores vpc.id, and reads the value via np provider read. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…loyed After writing service attributes, patch the service to set linkable_to: [] so it is not linkable to any scope type once created. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rm account provider Replace static region from values.yaml with a dynamic lookup using np provider list/read, reusing the single provider list call already made for vpc_id resolution. Export REGION from build_context so subsequent workflow steps receive it via environment output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…absent Dependency service contexts do not include .service.nrn; use .entity_nrn as fallback so account NRN resolution works for create/delete/update/link/unlink. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…jq queries Some providers have null data_source.stored_keys; using (... // []) before contains() prevents jq from throwing "Cannot iterate over null" when resolving account.region and vpc.id providers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ebug output Guard against null .results in np provider list JSON response. Add temporary debug log to inspect raw provider list output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When running inside a workflow, np provider list sends limit=0 which the API rejects with 400 (querystring/limit must be >= 1). Pass --limit 100 to ensure a valid paginated request. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ice_outputs
Comments out the `np service patch --body '{"linkable_to": []}'` call
instead of removing it, keeping the toggle easy to re-enable.
…erver Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…k workflows build_permissions_context was reading tfstate_bucket from values.yaml (which never defined it), causing an empty bucket name on terraform init during link and unlink actions. Align with rds-postgres-db pattern: export TFSTATE_BUCKET from build_context via workflow output and consume it from the environment. Added an explicit guard in build_permissions_context to fail fast if the var is missing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ed link When a link transitions to a failed state before fully materializing, its .link.attributes never receives the db_name parameter. Subsequent unlink actions then hit `ERROR: db_name is required to create a link` and the link gets stuck — user cannot retry nor remove it cleanly. Mirror the pattern from rds-postgres-db/scripts/aws/build_context (which sets LINK_NEVER_CREATED=true when .type == "delete" and there is no server hostname): on a delete action with missing db_name, log a warning and exit cleanly instead of failing the unlink workflow. The error is preserved for create/link actions, where missing db_name is still a user error. Reproduced on the Galicia POC (CLIEN-759): a second link test with invalid parameters left the link in failed state; the unlink could never clean it up. Pairs with #12 (TFSTATE_BUCKET propagation). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ate-bucket-link fix(rds-postgres-server): propagate TFSTATE_BUCKET through link/unlink workflows
…ame-on-unlink fix(rds-postgres-server): skip db_name check on unlink of never-created link
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d collision Both modules used the identical name nullplatform-<cluster_name>-rds-secretsmanager-policy for two different policies. IAM policy names are account-wide unique, so deploying both modules against the same cluster_name fails with EntityAlreadyExists — caught by an actual tofu apply against a real AWS account with both modules together.
… just values.yaml Confirmed via a live test against a real cluster: assume_role_step read an empty CONTEXT.providers["identity-access-control"] despite the provider being registered, because values.yaml alone doesn't get the platform to resolve it into CONTEXT for a given workflow run. scopes-static-files declares provider_categories per-workflow (via its initial.yaml, included by others) in addition to values.yaml — ported that here directly since services has no workflow include: mechanism.
…t CONTEXT.providers Confirmed via a live end-to-end test against a real agent/cluster (creating a real RDS instance): CONTEXT.providers["identity-access-control"] is never populated by this agent version, regardless of provider_categories declarations in values.yaml or the workflow YAML. build_context already proves np provider list/read work reliably on this same agent for account.region/vpc.id — this ports that exact pattern for the aws-iam-configuration provider (stored key iam_role_arns.arns), looked up at the service's namespace NRN, where the identity-access-control provider is registered. Live-verified end to end: agent assumed arn:aws:iam::235494813897:role/nullplatform-api-private-rds-postgres-server-role and successfully created aws_secretsmanager_secret, aws_db_subnet_group, aws_security_group, and aws_db_instance using that role's permissions (the agent's own role has no RDS/EC2 policies attached, so this could not have happened via the old direct-attachment model).
build_context creates its own np-service-<SERVICE_ID> tfstate bucket, same as rds-postgres-server, but the role only had the Secrets Manager policy. Confirmed via a live test: assuming this role and running build_context hit AccessDenied on s3:CreateBucket/PutBucketVersioning. Adds the same np-service-* scoped S3 policy rds-postgres-server already has.
np service list requires the exact NRN a service is scoped at. Stripping :application=... to derive a namespace-level NRN made auto-discovery always return zero results, even with a healthy matching rds-postgres-server — confirmed live by querying np service list at both levels directly.
…tions, not just primary Confirmed live: the EKS cluster's VPC has a secondary CIDR (100.17.0.0/16) for pod networking alongside the primary (10.16.0.0/16). Agent pods get IPs from the secondary block, but the RDS security group only allowed the primary CIDR (data.aws_vpc.main.cidr_block), silently blocking agent-pod-to-RDS connectivity — the postgresql provider hung indefinitely trying to reach the database during rds-postgres-db's create workflow.
…to-end testing Documents the 3 required pieces for AssumeRole to actually work (apply requirements/, grant the agent sts:AssumeRole, register an identity-access-control provider at the namespace NRN), the fail-open behavior when any piece is missing, the multi-CIDR VPC networking requirement, the auto-discovery NRN requirement for rds-postgres-db, and the orphaned-role edge case from partially-failed creates — all confirmed against a real cluster during this branch's validation.
… setup guides Adds the actual module blocks (service_requirements_*, vpc_provider, aws_cloud_provider) alongside the identity_access_control example already present, so the setup guide is a complete, copy-pasteable reference matching the pattern already validated in the services-testing sandbox.
- Generalize assume_role_lib to take override/default env var names as params (indirect expansion), making it identical and copy-paste reusable across rds-postgres-server and rds-postgres-db. - Pass --dimensions (from .service.dimensions) to the IAM provider lookup in assume_role_step, so a future per-dimension AssumeRole role at the same namespace NRN resolves the most-specific match instead of an arbitrary one. - Add policies_name_prefix override variable to requirements/ (server and db), preserving current default policy names. - Move requirements/ under specs/requirements/aws/ to match the services-s-3 layout convention. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nullplatform Mirrors the specs/install convention from nullplatform/scopes-static-files: requirements/ provisions the AWS AssumeRole IAM role/policies (the agent's half), install/ registers the service_definition + agent association (the platform's half) so np service create actually routes to an agent. Modeled on the module blocks already validated live against PAE/services-testing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ierarchy The assume_role_step stripped the NRN to namespace level and did a plain 'np provider list' filtered by stored_keys. A plain list does not inherit providers from ascendant NRN levels, so the identity-access-control provider (registered at account level) was never found and the step fell back to agent credentials (assume_role=skipped). Align with the aws-s3-bucket service: use the full NRN as-is and query with --categories identity-access-control, which resolves up the hierarchy and returns the effective provider attributes. Applies to both server and db.
Post-extraction cleanup after splitting rds-postgres-server/rds-postgres-db out of the nullplatform/services monorepo into their own repository: - Drop the databases/ path prefix (service_path, cp -r examples, module source URLs) now that both services live at the repo root. - Point requirements/install module source examples and repository_name defaults at this repo instead of nullplatform/services. - Add specs/install/aws support for the account-level aws-configuration, aws-networking-configuration and aws-iam-configuration providers (vpc_provider, aws_cloud_provider, identity_access_control), toggleable via create_account_providers/create_identity_access_control. Only rds-postgres-server's install creates identity_access_control — folds in rds-postgres-db's role ARN via a variable instead of letting db register its own second provider at the same NRN (which would make assume_role_step's lookup nondeterministic). - Fix README/install docs and a stale assume_role_step comment that still said the aws-iam-configuration provider is registered at namespace level: it's actually account level, per the --categories fix already merged to main (0ce7aa7) which walks up the NRN hierarchy from the service's NRN. - Add root .gitignore (Terraform/IDE artifacts) and README.md, and the PR-checks workflow (shellcheck + tofu fmt) that lived at the monorepo root and wasn't carried over by the path extraction. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…es-s-3 Replace the ad-hoc shellcheck+tofu-fmt workflow carried over from the services monorepo with the same reusable-workflow stack services-s-3 uses: branch-validation, conventional-commit, release (release-please), shellcheck, and trivy IaC scanning — all delegating to nullplatform/actions-nullplatform. Add .trivyignore suppressing AVD-AWS-0104 (unrestricted RDS security-group egress) on both services, mirroring services-s-3's own documented-suppression pattern: standard for an RDS instance's own SG, inbound is already restricted to 5432 from the VPC's CIDRs. Verified locally with trivy 0.68.2 (0 misconfigurations after the suppression) and shellcheck 0.11.0 (clean) using the same discovery logic as the reusable workflows. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Uses the 'ours' strategy so main's placeholder template (Dockerfile, README.md) is not reintroduced — this repo's tree is unchanged. Establishes a common ancestor so GitHub allows opening a PR against main.
sebastiancorrea81
deleted the
feature/import-rds-postgres-from-services-monorepo
branch
July 7, 2026 16:38
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
databases/rds-postgres-serveranddatabases/rds-postgres-dbfrom thenullplatform/servicesmonorepo into this dedicated repository, preserving their commit history, at the repo root (nodatabases/prefix).service_path, andrepository_namedefaults to point at this repo instead ofnullplatform/services.rds-postgres-server'sspecs/install/awswith the account-levelaws-configuration/aws-networking-configuration/aws-iam-configurationprovider registration (toggleable), foldingrds-postgres-db's AssumeRole role ARN into the sameidentity-access-controlprovider instead of letting each service register its own (which would makeassume_role_step's lookup nondeterministic).--categories(not namespace level, as originally documented)..gitignore,README.md, and adopts the same CI stack asnullplatform/services-s-3(branch-validation, conventional-commit, release-please, shellcheck, trivy IaC scan vianullplatform/actions-nullplatform), including a documented.trivyignoresuppression for the RDS security group's unrestricted egress (same class of findingservices-s-3suppresses for its own service).oursstrategy solely to give this branch a common ancestor withmain(required for PR creation) — no content from main's placeholder template was reintroduced.conventional-commitlinting (one non-conforming subject, one over-length header) — content/authorship/dates unchanged, only the message text.Test plan
tofu validate+tofu fmt -checkonrequirements/awsandspecs/install/awsfor both servicestrivy configlocally: 0 misconfigurations after the.trivyignoresuppressionshellchecklocally (matching the reusable workflow's discovery logic): cleanrds-postgres-serverrun live against a real nullplatform agent/AWS account before this extraction (see commit history) — real RDS instance provisioned and destroyed successfully with this code🤖 Generated with Claude Code